# 使用类和实例
# 可使用类来模拟现实世界中的很多情景。类编写好后，你的大部分时间将花在根据类创建的实例上。
# 你需要执行的一个重要任务是修改实例的属性。可以直接修改实例的属性，也可以编写方法以特定的方式进行修改。

# Car类
# 下面来编写一个表示汽车的类。它存储了有关汽车的信息，还有一个汇总这些信息的方法：
# car.py
class Car:
	"""一次模拟汽车的简单尝试"""

	def __init__(self, make, model, year):
		"""初始化描述汽车的属性"""
		self.make = make
		self.model = model
		self.year = year

	def get_descriptive_name(self):
		"""返回整洁的描述性信息"""
		long_name = f"{self.year} {self.make} {self.model}"
		return long_name.title()

my_new_car = Car('audi', 'a4', 2019)
print(my_new_car.get_descriptive_name())


# 给属性指定默认值
# 创建实例时，有些属性无须通过形参来定义，可在方法__init__() 中为其指定默认值。
# 下面来添加一个名为odometer_reading 的属性，其初始值总是为0。
# 我们还添加了一个名为read_odometer() 的方法，用于读取汽车的里程表
class Car:
	"""一次模拟汽车的简单尝试"""

	def __init__(self, make, model, year):
		"""初始化描述汽车的属性"""
		self.make = make
		self.model = model
		self.year = year
		self.odometer_reading = 0

	def get_descriptive_name(self):
		"""返回整洁的描述性信息"""
		long_name = f"{self.year} {self.make} {self.model}"
		return long_name.title()

	def read_odometer(self):
		"""打印一条指出汽车里程的消息"""
		print(f"This car has {self.odometer_reading} miles on it.")

my_new_car = Car('audi', 'a4', 2019)
print(my_new_car.get_descriptive_name())
my_new_car.read_odometer()


# 修改属性的值
# 我们能以三种方式修改属性的值：直接通过实例进行修改，通过方法进行设置，以及通过方法进行递增（增加特定的值）。
# 下面依次介绍这些方式。
# 直接修改属性的值
# 要修改属性的值，最简单的方式是通过实例直接访问它。下面的代码直接将里程表读数设置为23：
my_new_car.odometer_reading = 23      # 使用句点表示法直接访问并设置汽车的属性odometer_reading 。
# 这行代码让Python在实例my_new_car 中找到属性odometer_reading ，并将其值设置为23
my_new_car.read_odometer()

# 有时候需要像这样直接访问属性，但其他时候需要编写对属性进行更新的方法。


# 通过方法修改属性的值
# 如果有方法能替你更新属性，将大有裨益。这样就无须直接访问属性，而可将值传递给方法，由它在内部进行更新。
# 下面的示例演示了一个名为update_odometer() 的方法
class Car:
	"""一次模拟汽车的简单尝试"""

	def __init__(self, make, model, year):
		"""初始化描述汽车的属性"""
		self.make = make
		self.model = model
		self.year = year
		self.odometer_reading = 0

	def get_descriptive_name(self):
		"""返回整洁的描述性信息"""
		long_name = f"{self.year} {self.make} {self.model}"
		return long_name.title()

	def read_odometer(self):
		"""打印一条指出汽车里程的消息"""
		print(f"This car has {self.odometer_reading} miles on it.")

	def update_odometer(self, mileage):		# 方法update_odometer()接受一个里程值，并将其赋给self.odometer_reading
		"""将里程表读数设置为指定的值"""
		self.odometer_reading = mileage

my_new_car1 = Car('tesla', 'Model Y', 2020)
print(my_new_car1.get_descriptive_name())

my_new_car1.update_odometer(22)
my_new_car1.read_odometer()

# 对方法update_odometer() 进行扩展，使其在修改里程表读数时做些额外的工作。
# 下面来添加一些逻辑，禁止任何人将里程表读数往回调：
class Car:
	"""一次模拟汽车的简单尝试"""

	def __init__(self, make, model, year):
		"""初始化描述汽车的属性"""
		self.make = make
		self.model = model
		self.year = year
		self.odometer_reading = 0

	def get_descriptive_name(self):
		"""返回整洁的描述性信息"""
		long_name = f"{self.year} {self.make} {self.model}"
		return long_name.title()

	def read_odometer(self):
		"""打印一条指出汽车里程的消息"""
		print(f"This car has {self.odometer_reading} miles on it.")

	def update_odometer(self, mileage):		# 方法update_odometer()接受一个里程值，并将其赋给self.odometer_reading
		"""
		将里程表读数设置为指定的值
		禁止将里程表读数往回调	
		"""
		if mileage >= self.odometer_reading:
			self.odometer_reading = mileage
		else:
			print("You can't roll back an odometer!")
# update_odometer() 在修改属性前检查指定的读数是否合理。
# 如果新指定的里程（mileage ）大于或等于原来的里程（self.odometer_reading ），就将里程表读数改为新指定的里程
# 否则发出警告，指出不能将里程表往回调
my_new_car2 = Car('tesla', 'Model X', 2020)
print(my_new_car2.get_descriptive_name())

my_new_car2.update_odometer(22)
my_new_car2.read_odometer()
my_new_car2.update_odometer(21)		# 提示里程数不能回调
my_new_car2.update_odometer(25)
my_new_car2.read_odometer()


# 通过方法对属性的值进行递增
# 有时候需要将属性值递增特定的量，而不是将其设置为全新的值。
# 假设我们购买了一辆二手车，且从购买到登记期间增加了100英里的里程。
# 下面的方法让我们能够传递这个增量，并相应地增大里程表读数：
class Car:
	"""一次模拟汽车的简单尝试"""

	def __init__(self, make, model, year):
		"""初始化描述汽车的属性"""
		self.make = make
		self.model = model
		self.year = year
		self.odometer_reading = 0

	def get_descriptive_name(self):
		"""返回整洁的描述性信息"""
		long_name = f"{self.year} {self.make} {self.model}"
		return long_name.title()

	def read_odometer(self):
		"""打印一条指出汽车里程的消息"""
		print(f"This car has {self.odometer_reading} miles on it.")

	def update_odometer(self, mileage):		# 方法update_odometer()接受一个里程值，并将其赋给self.odometer_reading
		"""
		将里程表读数设置为指定的值
		禁止将里程表读数往回调	
		"""
		if mileage >= self.odometer_reading:
			self.odometer_reading = mileage
		else:
			print("You can't roll back an odometer!")

	def increment_odometer(self, miles):
		"""将里程表读数增加指定的量"""
		self.odometer_reading += miles

my_used_car = Car('subaru', 'outback', 2015)
print(my_used_car.get_descriptive_name())

my_used_car.update_odometer(23_500)
my_used_car.read_odometer()

my_used_car.increment_odometer(100)			# 调用increment_odometer() 并传入100 ，以增加从购买到登记期间行驶的100英里
my_used_car.read_odometer()

# 可以轻松地修改这个方法，以禁止增量为负值，从而防止有人利用它来回调里程表。
# 注意 　你可以使用类似于上面的方法来控制用户修改属性值（如里程表读数）的方式，
# 但能够访问程序的人都可以通过直接访问属性来将里程表修改为任何值。
# 要确保安全，除了进行类似于前面的基本检查外，还需特别注意细节。
